# 注册
from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.conf import settings
import random
from django_redis import get_redis_connection

from web import models
from Utils.Tencent.sms import send_sms_single
from Utils import encrypt
from Utils.bootstrap import BootStrapForm


class RegisterModelForm(BootStrapForm, forms.ModelForm):
    """
    用于注册Form
    """
    password = forms.CharField(
        widget=forms.PasswordInput(),
        label="输入密码",
        min_length=8,
        max_length=32,
        error_messages={"min_length": "密码长度至少为8位", "max_length": "密码长度最多为32位"},
    )  # 密码
    new_password = forms.CharField(
        widget=forms.PasswordInput(),
        label="确认密码",
        min_length=8,
        max_length=32,
        error_messages={"min_length": "密码长度至少为8位", "max_length": "密码长度最多为32位"},
    )
    # 注意正则表达式\d
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机号格式错误"), ])

    code = forms.CharField(label="验证码", widget=forms.TextInput())

    class Meta:  # 这个是form遍历出来的顺序
        model = models.UserInfo
        fields = ["username", "email", "password", "new_password", "mobile_phone", "code"]

    # 添加勾子函数，进行校验
    def clean_username(self):
        username = self.cleaned_data["username"]  # 获取fields里面的username表单
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError("名字已被注册！！！")
        return username

    def clean_email(self):
        email = self.cleaned_data["email"]
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError("邮箱已被注册！！！")
        return email

    # 将密码加密存入数据库中
    def clean_password(self):
        password = self.cleaned_data["password"]
        # 加密&返回
        return encrypt.md5(password)

    def clean_new_password(self):
        password = self.cleaned_data["password"]
        new_password = encrypt.md5(self.cleaned_data["new_password"])
        if password != new_password:
            raise ValidationError("再次密码输入不一致！！！")
        return new_password

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data["mobile_phone"]
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError("手机号已被注册！！！")
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data["code"]
        mobile_phone = self.cleaned_data.get("mobile_phone")
        if not mobile_phone:
            return code
        # 连接django-redis
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送")
        redis_str_code = redis_code.decode("utf-8")  # 刚获取出来的不是字符串类型,要解码
        if code.strip() != redis_str_code:
            raise ValidationError("验证码输入错误，请重新输入")
        return code


class SendSmsForm(forms.Form):
    """
    发送短信验证码的Form
    """
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """手机号校验的勾子"""
        mobile_phone = self.cleaned_data['mobile_phone']  # 获取参数

        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not template_id:
            raise ValidationError("爬虫爬虫快走开！！！")

        # 校验数据库中是否已有手机号
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        """
        如果是登录页面的话，就判断手机号是不是在数据库中(在数据库就表明被注册过，可以获取验证码)，
        如果是注册就是判断手机号是不是在数据库中(在数据库就表明手机已经被注册过，不能继续注册)"""
        if tpl == "login":
            if not exists:
                raise ValidationError("该手机号没有被注册")
        else:
            #
            if exists:
                raise ValidationError("该手机号已被注册")

        # 发送短信
        code = random.randrange(1000, 9999)  # 4位数的验证码
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        if sms['result'] != 0:  # 等于0就发送成功了
            raise ValidationError("短信发送失败,{}".format(sms['errmsg']))

        # 将手机号和验证码定入到redis中
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)  # 写入redis 存活时间为60s

        return mobile_phone


class LoginSMSForm(BootStrapForm, forms.Form):
    """用短信验证码登录"""
    mobile_phone = forms.CharField(label="手机号",
                                   validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机号格式错误"), ])

    code = forms.CharField(label="验证码", widget=forms.TextInput())

    # 对手机号进行校验
    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data["mobile_phone"]  # 获取手机号
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        # user_object = models.UserInfo.objects.filter(mobile_phone=mobile_phone).filter() # 获取的是数据库中的全部字段的信息
        if not exists:
            raise ValidationError("手机号不存在")
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data["code"]
        mobile_phone = self.cleaned_data["mobile_phone"]

        # 手机号不存在就不需要在校验了
        if not mobile_phone:
            return code

        # 连接radis,用手机号获取验证码
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送验证码")

        redis_str_code = redis_code.decode("utf-8")  # 转化验证码的格式
        if code.strip() != redis_str_code:  # 防止有空格的情况添加了strip()清除空格
            raise ValidationError("验证码错误，请重新输入")
        return code


class LoginForm(BootStrapForm, forms.Form):
    """用户登录验证码"""
    username = forms.CharField(label="手机号或邮箱")
    password = forms.CharField(label="密码", widget=forms.PasswordInput())  # render_value=True:保存密码的状态
    code = forms.CharField(label="图片验证码")

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self): # 返回密码加密
        pwd = self.cleaned_data['password']
        # 加密&返回
        return encrypt.md5(pwd)

    def clean_code(self):
        """ 钩子函数 图片验证码是否正确 """
        # 用户输入的验证码
        code = self.cleaned_data["code"]

        # 去session获取自己的验证码
        session_code = self.request.session.get("image_code")
        if not session_code:  # 没有获取到验证码
            raise ValidationError("验证码已经过期，请重新发送")
        if code.strip().upper() != session_code.strip().upper():
            raise ValidationError("验证码输入错误，请重新输入")
